﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using XHouse.Model.Escenas;

namespace XHouse.Model.Aparatos
{
    [Table("Aparato")]
    public class Aparato : Identity
    {
        /// <summary>
        /// Número de aparato.
        /// Este campo es distinto al identificador de la base de datos.
        /// Deberá permitirse ingresar el número, pero deberá chequearse que sea único.
        /// </summary>
        [Required(ErrorMessage = "El número del aparato es obligatorio")]
        [Range(1, int.MaxValue, ErrorMessage = "El numero de aparato tiene que ser un número entero")]
        public int Numero { get; set; }

        /// <summary>
        /// Nombre del aparato.
        /// Este nombre debería ser mas específico. Por ejemplo: "Pulsador del pasillo".
        /// </summary>
        [Required(ErrorMessage = "El campo Nombre es requerido.")]
        [MaxLength(100, ErrorMessage = "El Nombre no puede superar los 100 caracteres.")]
        public string Nombre { get; set; }

        [Display(Name = "Descripción")]
        [MaxLength(300, ErrorMessage = "La Descripción no puede superar los 300 caracteres.")]
        public string Descripcion { get; set; }

        [Display(Name = "Habilitado")]
        public bool Habilitado { get; set; }

        [Required(ErrorMessage = "Seleccione un tipo de aparáto válido.")]
        public int TipoAparatoId { get; set; }

        [ForeignKey("TipoAparatoId")]
        public TipoAparato TipoAparato { get; set; }

        [Required(ErrorMessage = "Seleccione una zona válida.")]
        public int ZonaId { get; set; }

        [ForeignKey("ZonaId")]
        public virtual Zona Zona { get; set; }

        [Required(ErrorMessage = "Seleccione el modulo al que se encuentra conectado el aparato.")]
        public int ModuloId { get; set; }

        [ForeignKey("ModuloId")]
        public Modulo Modulo { get; set; }

        [Required(ErrorMessage = "Seleccione el ambiente donde se encuentra el aparato.")]
        public int AmbienteId { get; set; }

        [ForeignKey("AmbienteId")]
        public Ambiente Ambiente { get; set; }

        [Display(Name = "Valor de estado actual")]
        [Column("EstadoActual")]
        public int EstadoActual { get; set; }

        /// <summary>
        /// Puerto al que está conectado el Aparato en el Módulo
        /// </summary>
        [Required(ErrorMessage = "El Puerto es obligatorio")]
        public int Puerto { get; set; }

        /// <summary>
        /// Posición del puerto en el que está conectado el Aparato
        /// </summary>
        [Required(ErrorMessage = "La Posición es obligatoria")]
        public int Posicion { get; set; }

        /// <summary>
        /// Posición X en del aparato en la imagen de la zona
        /// </summary>
        public int? PosicionX { get; set; }

        /// <summary>
        /// Posición Y en del aparato en la imagen de la zona
        /// </summary>
        public int? PosicionY { get; set; }

        [NotMapped]
        public bool Posicionado
        {
            get { return PosicionX.HasValue && PosicionY.HasValue; }
        }

        /// <summary>
        /// Triggers asociados al aparato
        /// </summary>
        public virtual ICollection<EscenaAparatoTrigger> AparatoTriggers { get; set; }

        /// <summary>
        /// Obtiene de manera rápida el estado actual
        /// del aparato: Deshabilitado, prendido y apagado.
        /// </summary>
        [NotMapped]
        public TipoEstado EstadoActualTipo
        {
            get
            {
                if (!Habilitado)
                    return TipoEstado.Deshabilitado;

                if (TipoAparato.PuedeApagarse && EstadoActual == TipoAparato.EstadoApagado)
                    return TipoEstado.Apagado;

                return TipoEstado.Encendido;
            }
        }

        public void Apagar()
        {
            if (!TipoAparato.PuedeApagarse)
                throw new InvalidOperationException(string.Format("Un aparato de tipo '{0}' no puede apagarse", TipoAparato.Nombre));

            EstadoActual = TipoAparato.EstadoApagado;
        }

        public void SetearEstado(int estado)
        {
            if (TipoAparato.Operacion == TipoOperacion.Binario && estado != TipoAparato.RangoTopeInferior && estado != TipoAparato.RangoTopeSuperior)
                throw new InvalidOperationException(
                    string.Format(
                        "Error al asignar el estado actual del aparato binario. Los valores posibles para el aparato {0} son: {1} y {2}.",
                        Nombre, TipoAparato.RangoTopeInferior, TipoAparato.RangoTopeSuperior));

            if (TipoAparato.Operacion == TipoOperacion.Gradual && (estado < TipoAparato.RangoTopeInferior || estado > TipoAparato.RangoTopeSuperior))
                throw new InvalidOperationException(
                    string.Format(
                        "Error al asignar el estado actual del aparato gradual. Los valores posibles para el aparato {0} van desde {1} a {2}.",
                        Nombre, TipoAparato.RangoTopeInferior, TipoAparato.RangoTopeSuperior));

            EstadoActual = estado;   
        }
    }

    public enum TipoEstado
    {
        Deshabilitado = -1,
        Apagado = 0,
        Encendido = 1
    }
}